/*
 * Copyright (c) 2013, www.dutycode.com. All rights reserved.
 * email:dutycode@gmail.com
 * 使用时，请保留此标示
 *
 */
package com.dutycode.beanutils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 对象复制，不同对象之间值复制。<br>
 * 注意：目前支持成员变量的类型仅为基本类型和String，不含集合类型以及自定义类型<br>
 * 支持类型如下：String, int, double, float, char,  long, boolean, byte, short;<br>
 * 提供以下工具方法：<br>
 * 1、{@link BeanUtils#transferMapToObj(Map, Object)}} 将Map转换成JavaBean<br>
 * 2、{@link BeanUtils#transferObjToMap(Object)} 将JavaBean转化成Map<br>
 * 3、{@link BeanUtils#copyProperties(Object, Object, boolean)} 拷贝源JavaBean到目标JavaBean对象中<br>
 * 4、{@link BeanUtils#copyProperties(Object, Object, boolean, Map)}拷贝源JavaBean到目标JavaBean中，根据对应关系进行拷贝。
 * 
 * @author Michael.Zhang
 * @date 2013-11-29
 * @since 1.0
 */
public class BeanUtils{
	
	/**
	 * JavaBean之间相互的拷贝 ,名称相同（根据ignoreCase来确定是否区分大小写）的成员变量将进行拷贝<br>
	 * 
	 * @param dest 目标JavaBean
	 * @param orign 源JavaBean
	 * @param ignoreCase <code>true<code> 忽略大小写， <code>false<code> 区分大小写
	 * @throws InvocationTargetException InvocationTargetException
	 * @throws IllegalArgumentException IllegalArgumentException
	 * @throws IllegalAccessException IllegalAccessException
	 */
	public static void copyProperties(Object dest, Object orign, boolean ignoreCase) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		
		if (dest == null)
			throw new IllegalArgumentException("dest bean is null");
		if (orign == null)
			throw new IllegalArgumentException("orign bean is null");
		
		Map<String,Object> destMap = transferObjToMap(dest);
		Map<String, Object> orignMap = transferObjToMap(orign);
		
		Set<String> destMapKey = destMap.keySet();
		Set<String> orignMapKey = orignMap.keySet();
		
		//处理dest和orign，将处理结果处理成map格式，用于后续转换
		if (ignoreCase){
			//忽略大小写
			for (String destKey : destMapKey){
				for (String orignKey : orignMapKey){
					if (destKey.toLowerCase().equals(orignKey.toLowerCase())){
						//dest中存在orign相同Key值
						destMap.put(destKey, orignMap.get(orignKey));
					}
				}
			}
		}else {
			//区分大小写
			for (String destKey : destMapKey){
				if (orignMapKey.contains(destKey)){
					//dest中存在orign相同Key值
					destMap.put(destKey, orignMap.get(destKey));
				}
			}
		}
		
		
		//设置Dest对象值
		dest = transferMapToObj(destMap,dest);
		
	}
	
	/**
	 * JavaBean之间相互的拷贝 ,名称相同（根据ignoreCase来确定是否区分大小写）的成员变量将进行拷贝<br>
	 * 为了方便使用，如果设置了converMap参数，则进行了对应关系，key值为目标JavaBean中成员变量名称，Value值
	 * 为源JavaBean中的成员变量名称，对应后，将进行值的拷贝。
	 * @param dest 目标对象
	 * @param orign 源对象
	 * @param ignoreCase 是否忽略大小写 true忽略大小写， false 不忽略大小写
	 * @param convertMap 目标对象和源对象对应关系 key:目标键值名称, value：源键值名称
	 * @throws InvocationTargetException InvocationTargetException
	 * @throws IllegalArgumentException IllegalArgumentException
	 * @throws IllegalAccessException IllegalAccessException
	 */
	public static void copyProperties(Object dest, Object orign, boolean ignoreCase, Map<String,Object> convertMap) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		//先处理名字一致的键值
		copyProperties(dest, orign, ignoreCase);
		
		//如果convertMap传递为空，则无需进行下面转换
		if (convertMap != null && convertMap.size() > 0){
			//处理对应关系的键值对
			Map<String,Object> destTmpMap = transferObjToMap(dest);
			Map<String,Object> orignTmpMap = transferObjToMap(orign);
			
			Set<String> converKeySet = convertMap.keySet();
			for (String key: converKeySet){
				destTmpMap.put(key, orignTmpMap.get(convertMap.get(key)));
			}
			//将Map转换成Object
			transferMapToObj(destTmpMap, dest);
		}
		
	}
	
	
	/**
	 * 将JavaBean转换成Map<br>
	 * 仅转换标准Javabean，非标准的javaBean将不能进行转换。
	 * @param obj JavaBean
	 * @return 转化之后的Map对象，key为成员变量名称，value为成员变量值。
	 * @throws InvocationTargetException InvocationTargetException
	 * @throws IllegalArgumentException IllegalArgumentException
	 * @throws IllegalAccessException IllegalAccessException
	 */
	public static Map<String,Object> transferObjToMap( Object obj) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		Map<String,Object> map = new HashMap<String,Object>();
		Class<? extends Object> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		Method[] methods = clazz.getDeclaredMethods();
		
		for (Method m: methods){
			for (Field f: fields){
				if (m.getName().toLowerCase().equals(("get" + f.getName()).toLowerCase())){
					Object o = m.invoke(obj, null);
					map.put(f.getName(), o);
				}
			}
		}
		return map;
	}
	
	/**
	 * 将Map转换成JavaBean对象<br>
	 * Map中key值将转化为JavaBean中的成员变量名称<br>
	 * value值将转化为JavaBean中成员变量set之后的值
	 * @param map 需要转换的Map对象
	 * @param obj 需要转换成的目标JavaBean
	 * @throws InvocationTargetException InvocationTargetException
	 * @throws IllegalArgumentException IllegalArgumentException
	 * @throws IllegalAccessException IllegalAccessException
	 */
	public static Object transferMapToObj(Map<String,Object> map,Object obj) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		Class<? extends Object> clazz = obj.getClass();
		Field[] fields = clazz.getDeclaredFields();
		Method[] methods = clazz.getDeclaredMethods();
		
		for (Method m: methods){
			for (Field f: fields){
				if (m.getName().toLowerCase().contains(("set" + f.getName()).toLowerCase())){
					m.invoke(obj, map.get(f.getName()));
				}
			}
		}
		
		return obj;
	}
	
	
	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
		
		OrignJavaBean orign = new OrignJavaBean();
		orign.setId(1);
		orign.setNaMe("ceshi");
		DestJavaBean dest = new DestJavaBean();
		copyProperties(dest, orign, true);
		System.out.println(dest);
		
	}
	
}
	
class DestJavaBean{
	private int id;
	private String name;
	private String other;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getOther() {
		return other;
	}
	public void setOther(String other) {
		this.other = other;
	}
	@Override
	public String toString() {
		return "id:" + id +" name: " + name + " other:" + other;
	}
	
	
}


class OrignJavaBean{
	private int id;
	private String naMe;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getNaMe() {
		return naMe;
	}
	public void setNaMe(String naMe) {
		this.naMe = naMe;
	}
	
}
